1 Run PCAnsgd for PWS populations

Using the ‘PWSonly’ sites (~770k snps) Running PCAngsd requires several steps

1.1 Analysis Steps

1.1.2 Using bcftools to subset the VCF file using prune.in file

1.1.3 Convert VCF to the beagle format and run PCAnsgd

#create vcf files with only prune.in sites

bcftools view -R Data/vcf/3pops_newMD2000_maf05_75_5_0.5_pruned.prune.in.sites.txt Data/vcf/3pops.MD2000_new.maf05.vcf.gz > Data/vcf/3pops_MD2000_maf05_pruned.vcf

bgzip /Data/vcf/3pops_MD2000_maf05_pruned.vcf

#Create beagle files (at farm: create_beagle.sh) - same scripts to obtain allele frequency can output beagle files as well (calulateAF_xx.sh)
#  angsd -GL -doGlf 2

angsd -out /home/ktist/ph/data/new_vcf/MD3000/3pops_MD2000_maf05 -fai /home/jamcgirr/ph/data/c_harengus/c.harengus.fa.fai -doGlf 2 -doMaf 3 -doMajorMinor 4 -doPost 1 -doGeno 2 -vcf-pl /home/ktist/ph/data/new_vcf/MD7000/3pops/3pops_PWS91_maf05.vcf.gz -ref /home/jamcgirr/ph/data/c_harengus/c.harengus.fa 

# Reformat the prune.in file

1.1.4 Craete a slurm script file to create beagle files

sink(paste0("../Data/Slurmscripts/create_beagle.sh"))
cat("#!/bin/bash -l\n")
cat(paste0("#SBATCH --job-name=beagle \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=8 \n"))
cat(paste0("#SBATCH --nodes=4 \n"))
cat(paste0("#SBATCH -e =beagle.err  \n"))
cat(paste0("#SBATCH --time=72:00:00  \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n\n")
cat("module load vcftools")     
cat("\n\n")
    
for (i in 1:26){
    cat(paste0("vcftools --gzvcf /home/ktist/ph/data/new_vcf/MD3000/3pops_MD2000_maf05_pruned.vcf.gz  --chr chr",i))
    cat(paste0(" --out /home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_c",i," --BEAGLE-PL \n"))
}

cat("\n")

#remove the head line and cat beagle files
for (i in 2:26){
    cat(paste0("sed -e '1, 1d' < /home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_c",i,".BEAGLE.PL > /home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_c",i,".2.BEAGLE.PL \n"))
}
cat("\n")

cat("cat /home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_c1.BEAGLE.PL ") 
for (i in 2:26){
    cat(paste0("/home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_c",i,".2.BEAGLE.PL "))
}
cat(paste0(" > /home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_BEAGLE.PL \n"))
cat("gzip /home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_BEAGLE.PL \n\n")

sink(NULL)

1.1.5 Craete a slurm script file to run pcansgd

# Run PCAangsd for the entire chromosomes and each chromosome
sink(paste0("../Data/Slurmscripts/runPCAnsgd.sh"))
cat("#!/bin/bash -l\n")
cat(paste0("#SBATCH --job-name=PCAnsgd \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=8 \n"))
cat(paste0("#SBATCH --nodes=4 \n"))
cat(paste0("#SBATCH -e PCAnsgd.err  \n"))
cat(paste0("#SBATCH --time=72:00:00  \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n\n")
cat("module load angsd \n")     
cat("module load deprecated/python \n")     
cat("module load deprecated/pcangsd")     
cat("\n\n")
    
cat("python /home/jamcgirr/apps/pcangsd/pcangsd.py -b /home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_BEAGLE.PL.gz -o /home/ktist/ph/data/angsd/PCAngsd/3pops_MD2000 -threads 16 \n")
sink(NULL)


# run each chromosome separately 
sink(paste0("../Data/Slurmscripts/runPCAnsgd_byChromosome.sh"))
cat("#!/bin/bash -l\n")
cat(paste0("#SBATCH --job-name=PCAnsgdC \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=8 \n"))
cat(paste0("#SBATCH --nodes=4 \n"))
cat(paste0("#SBATCH -e PCAnsgdbyChrom.err  \n"))
cat(paste0("#SBATCH --time=72:00:00  \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n\n")
cat("module load angsd \n")     
cat("module load deprecated/python \n")     
cat("module load deprecated/pcangsd")     
cat("\n\n")

for(i in 1:26){
    cat(paste0("python /home/jamcgirr/apps/pcangsd/pcangsd.py -beagle /home/ktist/ph/data/new_vcf/MD3000/beagle/3pops_MD2000_pruned_c",i,".BEAGLE.PL.gz -o /home/ktist/ph/data/angsd/PCAngsd/3pops_MD2000_c",i," -threads 24 \n"))
}

sink(NULL)

2 Results of PCAngsd

2.1 All chromosomes

pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pop_info<-pop_info[,c("Sample","Population.Year","pop","Year.Collected")]
colnames(pop_info)[4]<-"year"
pops<-unique(pop_info$Population.Year[grep("PWS|SS|TB",pop_info$Population.Year)])
pop3<-pop_info[pop_info$Population.Year %in% pops,]

pop3$year[pop3$year==2007|pop3$year==2006]<-"2006/2007"
pop3$year<-factor(pop3$year, levels=c(1991, 1996, "2006/2007", 2017))

C <- as.matrix(read.table(paste0("../Data/PCAangsd/3pops_MD2000.cov")))
e <- eigen(C)
pca <-data.frame(Sample=pop3$Sample, 
                 pop= pop3$pop,
                 year=pop3$year,
                 PC1=e$vectors[,1],PC2=e$vectors[,2],
                 PC3=e$vectors[,3],PC4=e$vectors[,4],
                 PC5=e$vectors[,5],PC6=e$vectors[,6],
                 PC7=e$vectors[,7],PC8=e$vectors[,8],
                 stringsAsFactors=FALSE)

prop_explained <- c()
for (s in e$values[1:10]) {
    #print(s / sum(e$values))
    prop_explained <- c(prop_explained,round(((s / sum(e$values))*100),2))
}
pca$pop<-factor(pca$pop, levels=c("PWS","SS","TB"))

ggplot()+
    geom_point(data = pca, aes(x = PC1, y = PC2, fill = pop, color = pop, shape=year), size = 1.8)+
    scale_fill_manual(values=paste0(cols[c(2,3,1)],"4D"), guide="none")+
    scale_color_manual(values=cols[c(2,3,1)], name="Population")+
    xlab(paste("PC 1: ", prop_explained[1],"%\n",sep = ""))+
    ylab(paste("PC 2: ", prop_explained[2],"%\n",sep = ""))+
    theme_bw()+
    scale_shape_manual(values=c(23,25,3,21), name="Year")
ggsave("../Output/PCA/3pop_allChromosomes.png", height = 3.8, width = 5.2, dpi=300)

2.2 Each chromosome separately

Plots<-list()
chr<-paste0("c", c(1:26))
for (i in 1:length(chr)){
    C <- as.matrix(read.table(paste0("../Data/PCAangsd/3pops_MD2000_",chr[i],".cov")))
    e <- eigen(C)
    pca <-data.frame(Sample=pop3$Sample, 
                     pop=pop3$pop,
                     year=pop3$year,
                     PC1=e$vectors[,1],PC2=e$vectors[,2],
                     PC3=e$vectors[,3],PC4=e$vectors[,4],
                     PC5=e$vectors[,5],PC6=e$vectors[,6],
                     PC7=e$vectors[,7],PC8=e$vectors[,8],
                     stringsAsFactors=FALSE)
    
    prop_explained <- c()
    for (s in e$values[1:10]) {
        prop_explained <- c(prop_explained,round(((s / sum(e$values))*100),2))
    }
    Plots[[i]]<-ggplot()+
                    geom_point(data = pca, aes(x = PC1, y = PC2, fill = pop, color = pop, shape=year), size = 2.5)+
                    scale_fill_manual(values=paste0(cols[c(2,3,1)],"4D"), guide="none")+
                    scale_color_manual(values=cols[c(2,3,1)], name="Population")+
                    xlab(paste("PC 1: ", prop_explained[1],"%\n",sep = ""))+
                    ylab(paste("PC 2: ", prop_explained[2],"%\n",sep = ""))+
                    theme_bw()+
                    scale_shape_manual(values=c(23,25,3,21), name="Year")+
                    ggtitle(paste0("Chr",i))+theme(legend.position = "none")
}
g <- arrangeGrob(do.call(grid.arrange, c(Plots, ncol=5)))
ggsave(g, file="../Output/PCA/3pops_MD2000_PCA_byChromosome.png",width = 35, height = 30)

{pdf("../Output/PCA/3pops_MD2000_PCA_byChromosome.pdf",width = 30, height = 30)
do.call(grid.arrange, c(Plots, ncol=5))
dev.off()
}

# Plot legends
   p<-ggplot()+
        geom_point(data = pca, aes(x = PC1, y = PC2, fill = pop, color = pop, shape=year), size = 2.5)+
        scale_fill_manual(values=paste0(cols[c(2,3,1)],"4D"), guide="none")+
        scale_color_manual(values=cols[c(2,3,1)], name="Population")+
        xlab(paste("PC 1: ", prop_explained[1],"%\n",sep = ""))+
        ylab(paste("PC 2: ", prop_explained[2],"%\n",sep = ""))+
        theme_bw()+
        scale_shape_manual(values=c(23,25,3,21), name="Year")+
        ggtitle(paste0("Chr",i))

as_ggplot(get_legend(p))
ggsave("../Output/PCA/3pops_MD2000_PCA_byChromosome_legend.png",width = 1.5, height = 5)

2.3 Color by Year

ycols<-c("#f2f0f7","#cbc9e2","#9e9ac8","#6a51a3")

Plots<-list()
chr<-paste0("c", c(1:26))
for (i in 1:length(chr)){
    C <- as.matrix(read.table(paste0("../Data/PCAangsd/3pops_MD2000_",chr[i],".cov")))
    e <- eigen(C)
    pca <-data.frame(Sample=pop3$Sample, 
                     pop=pop3$pop,
                     year=pop3$year,
                     PC1=e$vectors[,1],PC2=e$vectors[,2],
                     PC3=e$vectors[,3],PC4=e$vectors[,4],
                     PC5=e$vectors[,5],PC6=e$vectors[,6],
                     PC7=e$vectors[,7],PC8=e$vectors[,8],
                     stringsAsFactors=FALSE)
    
    prop_explained <- c()
    for (s in e$values[1:10]) {
        prop_explained <- c(prop_explained,round(((s / sum(e$values))*100),2))
    }
    
    Plots[[i]]<-ggplot()+
                    geom_point(data = pca, aes(x = PC1, y = PC2, fill = year, color = year, shape=pop), size = 2.5)+
                    scale_fill_manual(values=paste0(ycols,"4D"), guide="none")+
                    scale_color_manual(values=ycols, name="Year")+
                    xlab(paste("PC 1: ", prop_explained[1],"%\n",sep = ""))+
                    ylab(paste("PC 2: ", prop_explained[2],"%\n",sep = ""))+
                    theme_bw()+
                    scale_shape_manual(values=c(16,17,15), name="Population")+
                    ggtitle(paste0("Chr",i))+theme(legend.position = "none")
}

{pdf("../Output/PCA/3pops_MD2000_PCA_byChromosome_byYear_nolegends.pdf",width = 30, height = 30)
do.call(grid.arrange, c(Plots, ncol=5))
dev.off()
}

g <- arrangeGrob(do.call(grid.arrange, c(Plots, ncol=4)))
ggsave(g, file="../Output/PCA/3pops_MD2000_PCA_byChromosome_byYear.png",width = 35, height = 40)


# Save the legend
    p<-ggplot()+
            geom_point(data = pca, aes(x = PC1, y = PC2, fill = year, color = year, shape=pop), size = 2.5)+
            scale_fill_manual(values=paste0(ycols,"4D"), guide="none")+
            scale_color_manual(values=ycols, name="Year")+
            xlab(paste("PC 1: ", prop_explained[1],"%\n",sep = ""))+
            ylab(paste("PC 2: ", prop_explained[2],"%\n",sep = ""))+
            theme_bw()+
            scale_shape_manual(values=c(16,17,15), name="Population")+
            ggtitle(paste0("Chr",i))
as_ggplot(get_legend(p))
ggsave("../Output/PCA/3pops_MD2000_PCA_byChromosome_byYear_legend.png",width = 1.5, height = 5)




3 PCAnsgd Selection scan

3.1 File preps and running PCAngsd

#Divide the BEAGLE.PL file into each population

# BEAGLE.PL.gz files available upon request
bea<-fread("../Data/vcf/MD2000/3pops_MD2000_pruned_BEAGLE.PL.gz") 
pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pop_info<-pop_info[,c("Sample","Population.Year","pop","Year.Collected")]
colnames(pop_info)[4]<-"year"
pops<-unique(pop_info$Population.Year[grep("PWS|SS|TB",pop_info$Population.Year)])


# for each populations
pops3<-c("PWS","TB","SS")
for (i in 1:length(pops3)){
    colums<-grep(pops3[i], colnames(bea))
    vec<-c(1:3, colums)
    df<-bea[,..vec]
    write.table(df, file=gzfile(paste0("../Data/vcf/MD2000/", pops3[i],"_MD2000_pruned.BEAGLE.PL.gz")), sep="\t", quote = F, row.names = FALSE )
}



y1<-c("PWS07","PWS17","PWS91","PWS96")
comb1<-t(combn(y1, 2))
y2<-c("TB06","TB17","TB91","TB96")
comb2<-t(combn(y2, 2))
y3<-c("SS06","SS17","SS96")
comb3<-t(combn(y3, 2))
comb4<-data.frame(V1=c("PWS07","PWS17","PWS91","PWS96","PWS07","PWS17","PWS96","SS06","SS17","SS96"), V2=c("TB06","TB17","TB91","TB96","SS06","SS17","SS96","TB06","TB17","TB96"))
comb<-rbind(comb1,comb2,comb3, comb4)

for (i in 3:nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    col1<-grep(pop1, colnames(bea))
    col2<-grep(pop2, colnames(bea))
    vec<-c(1:3, col1, col2)
    df<-bea[,..vec]
    write.table(df, file=gzfile(paste0("../Data/vcf/MD2000/", pop1,"_",pop2,"_MD2000_pruned.BEAGLE.PL.gz")), sep="\t", quote = F, row.names = FALSE )
}


# Create slurm scripts
bfiles<-list.files("../Data/new_vcf/MD2000/", pattern="BEAGLE.PL.gz")

sink("../Data/Slurmscripts/pcansgd_selection_md2000.sh")
cat("#!/bin/bash -l")
cat("\n")
cat(paste0("#SBATCH --job-name=selection \n"))
cat(paste0("#SBATCH --mem=24G \n")) 
cat(paste0("#SBATCH --ntasks=8 \n")) 
cat(paste0("#SBATCH --nodes=4  \n")) 
cat(paste0("#SBATCH -e selection.err  \n"))
cat(paste0("#SBATCH --time=144:00:00  \n"))
#cat(paste0("#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc \n"))
#cat(paste0("#SBATCH --mail-type=ALL \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n")
cat("module load angsd
module load deprecated/python
module load deprecated/pcangsd")
cat("\n\n")

for (i in 1:length(bfiles)){
  fname<-gsub("_MD2000_pruned.BEAGLE.PL.gz",'', bfiles[i])
  cat(paste0("python /home/jamcgirr/apps/pcangsd/pcangsd.py -beagle /home/ktist/ph/data/new_vcf/MD3000/beagle/",bfiles[i]," -o /home/ktist/ph/data/angsd/selection/",fname,"_selection -selection -sites_save \n"))
}

sink(NULL)

#(ran pcansgd_selection_md2000.sh, pcansgd_selection_md2000_1.sh, pcansgd_selection_md2000_2.sh at Farm on 6/28/23)

3.2 Plot the results of each population

# Selection scan results are available at: OSF Storage: https://osf.io/wrca4 Data/PCAngsd/selection/

pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pop_info<-pop_info[,c("Sample","pop","Year.Collected")]
colnames(pop_info)[3]<-"year"


#######
### Selection ###
library(RcppCNPy) # Numpy library for R

## function for QQplot
qqchi<-function(x,...){
    lambda<-round(median(x)/qchisq(0.5,1),2)
    qqplot(qchisq((1:length(x)-0.5)/(length(x)),1),x,ylab="Observed",xlab="Expected",...);abline(0,1,col=2,lwd=2)
    legend("topleft",paste("lambda=",lambda))
}

### read in seleciton statistics (chi2 distributed)
# Each column reflect the selection statistics along a tested PC (they are χ²-distributed with 1 degree of freedom.)
s<-npyLoad("../Data/PCAangsd/selection/PWS_selection.selection.npy")

## make QQ plot to QC the test statistics
qqchi(s)
ncol(s)

## read positions 
p<-read.table("../Data/PCAangsd/selection/PWS_selection.sites",colC=c("factor","integer"),sep=":")
names(p)<-c("chr","pos")


# 1. 1 axis:
#convert test statistic to p-value
p$pval<-1-pchisq(s,1)
p$loc<-1:nrow(p)
p$pval.log<--log10(p$pval)

## make manhatten plot
plot(-log10(p$pval),col=p$chr,xlab="Chromosomes",main="Manhattan plot", pch=".")

# 2. if more than 1 axis (ncol(s)>1)
# p$pval1<-pval[,1]
# p$pval2<-pval[,2]
# p$loc<-1:nrow(p)
# p$pval1.log<--log10(p$pval1)
# p$pval2.log<--log10(p$pval2)

## make Manhattan plots
pops1<-c("PWS","SS","TB")
evens<-paste0("chr",seq(2,26, by=2))

for (i in 1:length(pops1)){
    s<-npyLoad(paste0("../Data/PCAangsd/selection/",pops1[i],"_selection.selection.npy"))
    p<-read.table(paste0("../Data/PCAangsd/selection/",pops1[i],"_selection.sites"),colC=c("factor","integer"),sep=":")
    names(p)<-c("chr","pos")

    n<-ncol(s)
    if (n==1){
        p$pval<-1-pchisq(s,1)
        p$loc<-1:nrow(p)
        p$pval.log<--log10(p$pval)
    }
    #count the number of sites per chromosomes
    poss<-data.frame(chr=paste0("chr",1:26))
    k=1
    for (j in 1:26){
        df<-p[p$chr==paste0("chr",j),]
        poss$start[j]<-k
        poss$end[j]<-k+nrow(df)-1
        k=k+nrow(df)
    }
    poss$x<-poss$start+(poss$end-poss$start)/2

    p$color<-"steelblue"
    p$color[p$chr %in% evens]<-"lightblue"
    ggplot(data=p, aes(x=loc, y=pval.log, color=color))+
        geom_point(size=0.1)+
        scale_color_manual(values=c("lightblue","steelblue"), guide='none')+
        scale_x_continuous(name="Chromosome position", breaks=poss$x, labels=1:26)+
        theme_classic()+ylab("-log10(p-value)")+
        ggtitle(pops1[i])
    ggsave(paste0("../Output/PCA/selection_MD2000/",pops1[i],"_selection_scan.png"), width=8, height=4,dpi=300)
           
}

# -log10(0.05) = 1.30103
# -log10(0.05/232644) #6.667722
###  Significant p-value for 232,644 loci is 6.67  ###

  • NO sites above 6.7

3.3 Plot results of pariwise comparison

y1<-c("PWS07","PWS17","PWS91","PWS96")
comb1<-t(combn(y1, 2))
y2<-c("TB06","TB17","TB91","TB96")
comb2<-t(combn(y2, 2))
y3<-c("SS06","SS17","SS96")
comb3<-t(combn(y3, 2))
comb<-rbind(comb1, comb2, comb3)

evens<-paste0("chr",seq(2,26, by=2))

for (i in 1:nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    s<-npyLoad(paste0("../Data/PCAangsd/selection/",pop1, "_",pop2,"_selection.selection.npy"))
    p<-read.table(paste0("../Data/PCAangsd/selection/",pop1, "_",pop2,"_selection.sites"),colC=c("factor","integer"),sep=":")
    names(p)<-c("chr","pos")

    n<-ncol(s)
    if (n==1){
        p$pval<-1-pchisq(s,1)
        p$loc<-1:nrow(p)
        p$pval.log<--log10(p$pval)
    }
    if (n>1){
        p$pval<-pval[,1]
        p$loc<-1:nrow(p)
        p$pval.log<--log10(p$pval)
    }
    #count the number of sites per chromosomes
    poss<-data.frame(chr=paste0("chr",1:26))
    k=1
    for (j in 1:26){
        df<-p[p$chr==paste0("chr",j),]
        poss$start[j]<-k
        poss$end[j]<-k+nrow(df)-1
        k=k+nrow(df)
    }
    poss$x<-poss$start+(poss$end-poss$start)/2

    p$color<-"steelblue"
    p$color[p$chr %in% evens]<-"lightblue"
    ggplot(data=p, aes(x=loc, y=pval.log, color=color))+
        geom_point(size=0.1)+
        scale_color_manual(values=c("lightblue","steelblue"), guide='none')+
        scale_x_continuous(name="Chromosome position", breaks=poss$x, labels=1:26)+
        theme_classic()+ylab("-log10(p-value)")+
        ggtitle(paste0(pop1, " - ", pop2))
    ggsave(paste0("../Output/PCA/selection_MD2000/",pop1, "_",pop2,"_selection_scan.png"), width=8, height=4,dpi=300)
}




4 NGSadmix

4.1 Run NGSadmix (at Farm or locally)

  • NGSadmix_md2000_1.sh,NGSadmix_md2000_2.sh,NGSadmix_md2000_3.sh

4.2 Run CLUMPAL to find best K

  • (The best K =3)

4.2.1 Compile all likelihood numbers from log files into 1 (logfile)

#linux code (won't work with unix)
(for log in `ls *.log`; do grep -oP '3pops_pruned_maf05_\K[^ ]+|like=\K[^ ]+' $log; done) > 3pops_logfile_k3
(for log in `ls *.log`; do grep -oP '3pps_pruned_maf05_\K[^ ]+|like=\K[^ ]+' $log; done) > 3pops_logfile_k2
(for log in `ls *.log`; do grep -oP '3pops_pruned_maf05_\K[^ ]+|like=\K[^ ]+' $log; done) > 3pops_logfile_k4

4.3 Read ‘logfile’ & create an input file for Clumpak

log2<-read.table("../Data/ngsadmix/3pops_logfile_k2", sep="\t", header =FALSE)
log3<-read.table("../Data/ngsadmix/3pops_logfile_k3", sep="\t", header =FALSE)
log4<-read.table("../Data/ngsadmix/3pops_logfile_k4", sep="\t", header =FALSE)
log4<-data.frame(log4[c(FALSE,TRUE),])

logs<-data.frame(K=c(rep(2, times=10),rep(3, times=10),rep(4, times=10)), Liklihood=c(log2$V1,log3$V1, log4))
write.table(logs, "../Output/ngsadmix/3popslogs.txt", sep="\t", row.names = F, col.names = F, quote=F)
# DO NOT use special character in the file name
# Must have at least three K values

# upload the logs.txt to Clumpak website
# http://clumpak.tau.ac.il

#'Estimating the Best K (from Clumpak)'
#Wed Jul  5 20:15:52 2023: Ln'(3) = 277336.622395895
#Wed Jul  5 20:15:52 2023: Ln'(4) = 264322.030625194
#Wed Jul  5 20:15:52 2023: |Ln''(K=3)| = 13014.5917707011
#Wed Jul  5 20:15:52 2023: Delta(K=3) = 130.085671688741
#Wed Jul  5 20:15:52 2023: Max Delta K: 130.085671688741
#Wed Jul  5 20:15:52 2023: Optimal K by Evanno is: 3
#Wed Jul  5 20:15:56 2023: Using median values of Ln Prob of Data to calculate Prob(K=k):
#Wed Jul  5 20:15:56 2023: Prob(K=2) = 0
#Wed Jul  5 20:15:56 2023: Prob(K=3) = 0
#Wed Jul  5 20:15:56 2023: Prob(K=4) = 1
#Wed Jul  5 20:15:56 2023: Max Probability: 1
#Wed Jul  5 20:15:56 2023: The k for which Prob(K=k) obtains the highest value is: 4
#
#
#

  • 2 makes more sense than 3 but the reuslts chose “K=3” as the best

4.4 Run evalAdmix

#Create bash scripts to run locally
sink("../Data/Slurmscripts/evalAdmix_runlocal.sh")
cat("#!/bin/bash\n\n")

for (i in 2:3){
    cat("evalAdmix -beagle Data/new_vcf/MD2000/beagle/3pops_MD2000_pruned_BEAGLE.PL.gz ")
    cat(paste0("-fname Data/ngsadmix/3pops_pruned_maf05_k",i,"_run1.fopt.gz "))
    cat(paste0("-qname Data/ngsadmix/3pops_pruned_maf05_k",i,"_run1.qopt "))
    cat("-P 10 ")
    cat(paste0("-o Data/ngsadmix/evaladmix/output.corres.k",i,".txt\n"))
}
sink(NULL)

5 Plot results

source("visFuns.R")

#Output files
qfiles<-list.files("../Data/ngsadmix/",pattern="_run1.qopt")
ofiles<-list.files("../Data/ngsadmix/evaladmix/",pattern="output.corres")

#population info
pop<-read.csv("../Data/Sample_metadata_892pops.csv")
pop<-pop[grep("PWS|SS|TB", pop$pop),]
pop$Population.Year<-factor(pop$Population.Year, levels=c("TB91","TB96","TB06","TB17","PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17"))
poporder<-paste(pop$Population.Year[order(pop$Population.Year)])
pop_order<-c("TB91","TB96","TB06","TB17","PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17")

for (i in 1:length(qfiles)){
    # extract K from the file name
    if (i!=3) {
        oname<-ofiles[i]
        k<-gsub("[^0-9.]", "", ofiles[i])
        k<-as.integer(gsub("\\.",'',k))
    }
    if (i==3) k=3
    
    #read the qopt file for k=k
    q<-read.table(paste0("../Data/ngsadmix/", qfiles[i]))
    
    #order according to population and plot the NGSadmix results
    q$id<-pop$Population.Year
    q<-q[order(q$id),]
    
    ord<-orderInds(pop = as.vector(poporder), q = q[,1:(i+1)])
    
    xlabels<-data.frame(x=tapply(1:length(poporder),list(poporder), mean))
    xlabels$pop<-factor(rownames(xlabels), levels=pop_order)
    xlabels<-xlabels[order(xlabels$pop),]
    
    #color assignment
    if (i==1) colors=cols[c(1,2)]
    if (i==2) colors=cols[c(1,6,2) ]
    if (i==3) colors=cols[c(1,6,2,3) ]

    {png(paste0("../Output/ngsadmix/3pops_Admix_plot_k",k,".png"), height = 3.5, width=8, unit="in", res=300)
    barplot(t(q[,1:(i+2)])[,ord],col=colors,space=0,border=NA,xaxt="n",xlab="",ylab=paste0("Admixture proportions for K=",k))
    text(xlabels$x,-0.05,xlabels$pop,xpd=T, srt=90, adj=1,cex=0.8)
    abline(v=cumsum(sapply(unique(poporder[ord]),function(x){sum(pop[ord,"Population.Year"]==x)})),col=1,lwd=1.2)
    dev.off()}
    
    #Plot the correlation matrix from evalAdmix
    if (i!=3) {
        r<-read.table(paste0("../Data/ngsadmix/evaladmix/",ofiles[i]))
    
    # Plot correlation of residuals
    {pdf(paste0("../Output/ngsadmix/3pops_evalAdmix_corplot_k",k,".pdf"), height = 8, width=10)
    plotCorRes(cor_mat = r, pop = as.vector(pop[,"Population.Year"]), ord = ord, title=paste0("Evaluation of admixture proportions with K=",k), max_z=0.1, min_z=-0.1)
    dev.off()}
    }
}

# plot all 10 replicates for k=3
qfiles<-list.files("../Data/ngsadmix/",pattern="^3pops_pruned_maf05_k3+.*.qopt")
for (i in 2:10){
    q<-read.table(paste0("../Data/ngsadmix/", qfiles[i]))
    
    #order according to population and plot the NGSadmix results
    q$id<-pop$Population.Year
    q<-q[order(q$id),]
    
    ord<-orderInds(pop = as.vector(poporder), q = q[,1:3])
    
    xlabels<-data.frame(x=tapply(1:length(poporder),list(poporder), mean))
    xlabels$pop<-factor(rownames(xlabels), levels=pop_order)
    xlabels<-xlabels[order(xlabels$pop),]
    
    #color assignment
    colors=cols[c(1,6,2)]
    
    {png(paste0("../Output/ngsadmix/3pops_Admix_k3_rep",i,".png"), height = 3.5, width=8, unit="in", res=300)
    barplot(t(q[,1:3])[,ord],col=colors,space=0,border=NA,xaxt="n",xlab="",ylab=paste0("Admixture proportions for K=",k), main=paste0("rep",i))
    text(xlabels$x,-0.05,xlabels$pop,xpd=T, srt=90, adj=1,cex=0.8)
    abline(v=cumsum(sapply(unique(poporder[ord]),function(x){sum(pop[ord,"Population.Year"]==x)})),col=1,lwd=1.2)
    dev.off()}
}
LS0tCnRpdGxlOiAiUENBbmdzZC9OR1NhZG1peCIKb3V0cHV0IjogaHRtbF9ub3RlYm9vawpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgICAgdG9jOiB0cnVlIAogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICAgIHRoZW1lOiBsdW1lbgogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBkZl9wcmludDogcGFnZWQKLS0tCiMgUnVuIFBDQW5zZ2QgZm9yIFBXUyBwb3B1bGF0aW9ucyAKVXNpbmcgdGhlICdQV1Nvbmx5JyBzaXRlcyAofjc3MGsgc25wcykgClJ1bm5pbmcgUENBbmdzZCByZXF1aXJlcyBzZXZlcmFsIHN0ZXBzCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNvdXJjZSgiQmFzZVNjcmlwdHMuUiIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShrbml0cikKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZ2dwdWJyKQpnY29sczwtYygnI2ZmZmZiMycsJyM4ZGQzYzcnLCcjYmViYWRhJykKYGBgCgojIyBBbmFseXNpcyBTdGVwcwojIyMgUHJ1bmUgU05QczogVXNpbmcgUGxpbmsgdG8gcHJ1bmUgaGlnaGx5IGxpbmtlZCBzbnBzICAKKiBOZWVkIHRvIHJlZm9ybWF0IHRoZSBvdXRwdXQgKHh4eC5wcnVuZS5pbikgZmlsZSB0byBzdWJzZXQgYSB2Y2YgZmlsZSAocmF0aGVyIHRoYW4gdXNpbmcgaXQgZm9yICBwcnVpbmcgYSBwZWQvYmVkIGZpbGUpIApgYGB7YmFzaCBldmFsPUZBTFNFLCBlY2hvPVRSVUV9CiMgdmNmIGZpbGVzIG5vdCBpbiB0aGUgcmVwb3NpdG9yeSBhcmUgYXZhaWxhYmxlIGF0OiBPU0YgU3RvcmFnZTogaHR0cHM6Ly9vc2YuaW8vd3JjYTQgRGF0YS92Y2YvCgoKI2ZpcnN0IGNyZWF0ZSBwZWQvYmVkIGZpbGVzIHdpdGggYWRkaW5nIHZhcmlhbnQgaWQKI2FkZCB2YXJpYW50IGlkICYgY3JlYXRlIHBlZC9iZWQgZmlsZXMKcGxpbmsgLS12Y2YgRGF0YS92Y2YvM3BvcHMuTUQyMDAwX25ldy5tYWYwNS52Y2YuZ3ogLS1zZXQtbWlzc2luZy12YXItaWRzIEA6I1twaF1cXCRyLFxcJGEgLS1tYWtlLWJlZCAtLW91dCBEYXRhL25ld192Y2YvTUQzMDAwLzNwb3BzX25ld01EMjAwMF9tYWYwNQoKcGxpbmsgLS1iZmlsZSBEYXRhL3ZjZi8zcG9wc19uZXdNRDIwMDBfbWFmMDUgLS1yZWNvZGUgLS10YWIgLS1vdXQgRGF0YS92Y2YvM3BvcHNfbmV3TUQyMDAwX21hZjA1CgojZmluZCBoaWdobHkgY29ycmVsYXRlZCBzaXRlcyBmb3IgcHJ1bmluZwpwbGluayAtLWZpbGUgRGF0YS92Y2YvM3BvcHNfbmV3TUQyMDAwX21hZjA1IC0taW5kZXAtcGFpcndpc2UgNzUna2InIDUgMC41IC0tb3V0IERhdGEvbmV3X3ZjZi9NRDMwMDAvM3BvcHNfbmV3TUQyMDAwX21hZjA1Xzc1XzVfMC41X3BydW5lZAoKYGBgCgoKKiBSZWZvcm1hdCB0aGUgcHJ1bmUuaW4gZmlsZQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojUmVmb3JtYXQgcHJ1bi5pbiBmaWxlIHdpdGggcnVubmluZyB0aGUgcmVmb3JtYXRfcHJ1bmluLlIKc291cmNlKCJyZWZvcm1hdF9wcnVuaW4uUiIpCnJlZm9ybWF0X3BydW5pbigiLi4vRGF0YS92Y2YvM3BvcHNfbmV3TUQyMDAwX21hZjA1Xzc1XzVfMC41X3BydW5lZC5wcnVuZS5pbiIpCgojT3V0cHV0IGluIC4uL0RhdGEvdmNmLzNwb3BzX25ld01EMjAwMF9tYWYwNV83NV81XzAuNV9wcnVuZWQucHJ1bmUuaW4uc2l0ZXMudHh0CmBgYAoKIyMjIFVzaW5nIGJjZnRvb2xzIHRvIHN1YnNldCB0aGUgVkNGIGZpbGUgdXNpbmcgcHJ1bmUuaW4gZmlsZQoKIyMjIENvbnZlcnQgVkNGIHRvIHRoZSBiZWFnbGUgZm9ybWF0IGFuZCBydW4gUENBbnNnZAoKYGBge2Jhc2ggZXZhbD1GQUxTRSwgZWNobz1UUlVFfQojY3JlYXRlIHZjZiBmaWxlcyB3aXRoIG9ubHkgcHJ1bmUuaW4gc2l0ZXMKCmJjZnRvb2xzIHZpZXcgLVIgRGF0YS92Y2YvM3BvcHNfbmV3TUQyMDAwX21hZjA1Xzc1XzVfMC41X3BydW5lZC5wcnVuZS5pbi5zaXRlcy50eHQgRGF0YS92Y2YvM3BvcHMuTUQyMDAwX25ldy5tYWYwNS52Y2YuZ3ogPiBEYXRhL3ZjZi8zcG9wc19NRDIwMDBfbWFmMDVfcHJ1bmVkLnZjZgoKYmd6aXAgL0RhdGEvdmNmLzNwb3BzX01EMjAwMF9tYWYwNV9wcnVuZWQudmNmCgojQ3JlYXRlIGJlYWdsZSBmaWxlcyAoYXQgZmFybTogY3JlYXRlX2JlYWdsZS5zaCkgLSBzYW1lIHNjcmlwdHMgdG8gb2J0YWluIGFsbGVsZSBmcmVxdWVuY3kgY2FuIG91dHB1dCBiZWFnbGUgZmlsZXMgYXMgd2VsbCAoY2FsdWxhdGVBRl94eC5zaCkKIyAgYW5nc2QgLUdMIC1kb0dsZiAyCgphbmdzZCAtb3V0IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDMwMDAvM3BvcHNfTUQyMDAwX21hZjA1IC1mYWkgL2hvbWUvamFtY2dpcnIvcGgvZGF0YS9jX2hhcmVuZ3VzL2MuaGFyZW5ndXMuZmEuZmFpIC1kb0dsZiAyIC1kb01hZiAzIC1kb01ham9yTWlub3IgNCAtZG9Qb3N0IDEgLWRvR2VubyAyIC12Y2YtcGwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC8zcG9wcy8zcG9wc19QV1M5MV9tYWYwNS52Y2YuZ3ogLXJlZiAvaG9tZS9qYW1jZ2lyci9waC9kYXRhL2NfaGFyZW5ndXMvYy5oYXJlbmd1cy5mYSAKCiMgUmVmb3JtYXQgdGhlIHBydW5lLmluIGZpbGUKYGBgCgojIyMgQ3JhZXRlIGEgc2x1cm0gc2NyaXB0IGZpbGUgdG8gY3JlYXRlIGJlYWdsZSBmaWxlcyAgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvY3JlYXRlX2JlYWdsZS5zaCIpKQpjYXQoIiMhL2Jpbi9iYXNoIC1sXG4iKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tam9iLW5hbWU9YmVhZ2xlIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1tZW09MTZHIFxuIikpIApjYXQocGFzdGUwKCIjU0JBVENIIC0tbnRhc2tzPTggXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW5vZGVzPTQgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtZSA9YmVhZ2xlLmVyciAgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLXRpbWU9NzI6MDA6MDAgIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLXAgaGlnaCAgXG4iKSkKY2F0KCJcblxuIikKY2F0KCJtb2R1bGUgbG9hZCB2Y2Z0b29scyIpICAgICAKY2F0KCJcblxuIikKICAgIApmb3IgKGkgaW4gMToyNil7CiAgICBjYXQocGFzdGUwKCJ2Y2Z0b29scyAtLWd6dmNmIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDMwMDAvM3BvcHNfTUQyMDAwX21hZjA1X3BydW5lZC52Y2YuZ3ogIC0tY2hyIGNociIsaSkpCiAgICBjYXQocGFzdGUwKCIgLS1vdXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01EMzAwMC9iZWFnbGUvM3BvcHNfTUQyMDAwX3BydW5lZF9jIixpLCIgLS1CRUFHTEUtUEwgXG4iKSkKfQoKY2F0KCJcbiIpCgojcmVtb3ZlIHRoZSBoZWFkIGxpbmUgYW5kIGNhdCBiZWFnbGUgZmlsZXMKZm9yIChpIGluIDI6MjYpewogICAgY2F0KHBhc3RlMCgic2VkIC1lICcxLCAxZCcgPCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQzMDAwL2JlYWdsZS8zcG9wc19NRDIwMDBfcHJ1bmVkX2MiLGksIi5CRUFHTEUuUEwgPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQzMDAwL2JlYWdsZS8zcG9wc19NRDIwMDBfcHJ1bmVkX2MiLGksIi4yLkJFQUdMRS5QTCBcbiIpKQp9CmNhdCgiXG4iKQoKY2F0KCJjYXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01EMzAwMC9iZWFnbGUvM3BvcHNfTUQyMDAwX3BydW5lZF9jMS5CRUFHTEUuUEwgIikgCmZvciAoaSBpbiAyOjI2KXsKICAgIGNhdChwYXN0ZTAoIi9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDMwMDAvYmVhZ2xlLzNwb3BzX01EMjAwMF9wcnVuZWRfYyIsaSwiLjIuQkVBR0xFLlBMICIpKQp9CmNhdChwYXN0ZTAoIiA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDMwMDAvYmVhZ2xlLzNwb3BzX01EMjAwMF9wcnVuZWRfQkVBR0xFLlBMIFxuIikpCmNhdCgiZ3ppcCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQzMDAwL2JlYWdsZS8zcG9wc19NRDIwMDBfcHJ1bmVkX0JFQUdMRS5QTCBcblxuIikKCnNpbmsoTlVMTCkKYGBgCgojIyMgQ3JhZXRlIGEgc2x1cm0gc2NyaXB0IGZpbGUgdG8gcnVuIHBjYW5zZ2QgIApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBSdW4gUENBYW5nc2QgZm9yIHRoZSBlbnRpcmUgY2hyb21vc29tZXMgYW5kIGVhY2ggY2hyb21vc29tZQpzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvcnVuUENBbnNnZC5zaCIpKQpjYXQoIiMhL2Jpbi9iYXNoIC1sXG4iKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tam9iLW5hbWU9UENBbnNnZCBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tbWVtPTE2RyBcbiIpKSAKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW50YXNrcz04IFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1ub2Rlcz00IFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLWUgUENBbnNnZC5lcnIgIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS10aW1lPTcyOjAwOjAwICBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC1wIGhpZ2ggIFxuIikpCmNhdCgiXG5cbiIpCmNhdCgibW9kdWxlIGxvYWQgYW5nc2QgXG4iKSAgICAgCmNhdCgibW9kdWxlIGxvYWQgZGVwcmVjYXRlZC9weXRob24gXG4iKSAgICAgCmNhdCgibW9kdWxlIGxvYWQgZGVwcmVjYXRlZC9wY2FuZ3NkIikgICAgIApjYXQoIlxuXG4iKQogICAgCmNhdCgicHl0aG9uIC9ob21lL2phbWNnaXJyL2FwcHMvcGNhbmdzZC9wY2FuZ3NkLnB5IC1iIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDMwMDAvYmVhZ2xlLzNwb3BzX01EMjAwMF9wcnVuZWRfQkVBR0xFLlBMLmd6IC1vIC9ob21lL2t0aXN0L3BoL2RhdGEvYW5nc2QvUENBbmdzZC8zcG9wc19NRDIwMDAgLXRocmVhZHMgMTYgXG4iKQpzaW5rKE5VTEwpCgoKIyBydW4gZWFjaCBjaHJvbW9zb21lIHNlcGFyYXRlbHkgCnNpbmsocGFzdGUwKCIuLi9EYXRhL1NsdXJtc2NyaXB0cy9ydW5QQ0Fuc2dkX2J5Q2hyb21vc29tZS5zaCIpKQpjYXQoIiMhL2Jpbi9iYXNoIC1sXG4iKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tam9iLW5hbWU9UENBbnNnZEMgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW1lbT0xNkcgXG4iKSkgCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1udGFza3M9OCBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tbm9kZXM9NCBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC1lIFBDQW5zZ2RieUNocm9tLmVyciAgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLXRpbWU9NzI6MDA6MDAgIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLXAgaGlnaCAgXG4iKSkKY2F0KCJcblxuIikKY2F0KCJtb2R1bGUgbG9hZCBhbmdzZCBcbiIpICAgICAKY2F0KCJtb2R1bGUgbG9hZCBkZXByZWNhdGVkL3B5dGhvbiBcbiIpICAgICAKY2F0KCJtb2R1bGUgbG9hZCBkZXByZWNhdGVkL3BjYW5nc2QiKSAgICAgCmNhdCgiXG5cbiIpCgpmb3IoaSBpbiAxOjI2KXsKICAgIGNhdChwYXN0ZTAoInB5dGhvbiAvaG9tZS9qYW1jZ2lyci9hcHBzL3BjYW5nc2QvcGNhbmdzZC5weSAtYmVhZ2xlIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDMwMDAvYmVhZ2xlLzNwb3BzX01EMjAwMF9wcnVuZWRfYyIsaSwiLkJFQUdMRS5QTC5neiAtbyAvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL1BDQW5nc2QvM3BvcHNfTUQyMDAwX2MiLGksIiAtdGhyZWFkcyAyNCBcbiIpKQp9CgpzaW5rKE5VTEwpCgpgYGAKCgojIFJlc3VsdHMgb2YgUENBbmdzZCAKIyMgQWxsIGNocm9tb3NvbWVzICAKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcG9wX2luZm88LXJlYWQuY3N2KCIuLi9EYXRhL1NhbXBsZV9tZXRhZGF0YV84OTJwb3BzLmNzdiIpCnBvcF9pbmZvPC1wb3BfaW5mb1ssYygiU2FtcGxlIiwiUG9wdWxhdGlvbi5ZZWFyIiwicG9wIiwiWWVhci5Db2xsZWN0ZWQiKV0KY29sbmFtZXMocG9wX2luZm8pWzRdPC0ieWVhciIKcG9wczwtdW5pcXVlKHBvcF9pbmZvJFBvcHVsYXRpb24uWWVhcltncmVwKCJQV1N8U1N8VEIiLHBvcF9pbmZvJFBvcHVsYXRpb24uWWVhcildKQpwb3AzPC1wb3BfaW5mb1twb3BfaW5mbyRQb3B1bGF0aW9uLlllYXIgJWluJSBwb3BzLF0KCnBvcDMkeWVhcltwb3AzJHllYXI9PTIwMDd8cG9wMyR5ZWFyPT0yMDA2XTwtIjIwMDYvMjAwNyIKcG9wMyR5ZWFyPC1mYWN0b3IocG9wMyR5ZWFyLCBsZXZlbHM9YygxOTkxLCAxOTk2LCAiMjAwNi8yMDA3IiwgMjAxNykpCgpDIDwtIGFzLm1hdHJpeChyZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9QQ0FhbmdzZC8zcG9wc19NRDIwMDAuY292IikpKQplIDwtIGVpZ2VuKEMpCnBjYSA8LWRhdGEuZnJhbWUoU2FtcGxlPXBvcDMkU2FtcGxlLCAKICAgICAgICAgICAgICAgICBwb3A9IHBvcDMkcG9wLAogICAgICAgICAgICAgICAgIHllYXI9cG9wMyR5ZWFyLAogICAgICAgICAgICAgICAgIFBDMT1lJHZlY3RvcnNbLDFdLFBDMj1lJHZlY3RvcnNbLDJdLAogICAgICAgICAgICAgICAgIFBDMz1lJHZlY3RvcnNbLDNdLFBDND1lJHZlY3RvcnNbLDRdLAogICAgICAgICAgICAgICAgIFBDNT1lJHZlY3RvcnNbLDVdLFBDNj1lJHZlY3RvcnNbLDZdLAogICAgICAgICAgICAgICAgIFBDNz1lJHZlY3RvcnNbLDddLFBDOD1lJHZlY3RvcnNbLDhdLAogICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCgpwcm9wX2V4cGxhaW5lZCA8LSBjKCkKZm9yIChzIGluIGUkdmFsdWVzWzE6MTBdKSB7CiAgICAjcHJpbnQocyAvIHN1bShlJHZhbHVlcykpCiAgICBwcm9wX2V4cGxhaW5lZCA8LSBjKHByb3BfZXhwbGFpbmVkLHJvdW5kKCgocyAvIHN1bShlJHZhbHVlcykpKjEwMCksMikpCn0KcGNhJHBvcDwtZmFjdG9yKHBjYSRwb3AsIGxldmVscz1jKCJQV1MiLCJTUyIsIlRCIikpCgpnZ3Bsb3QoKSsKICAgIGdlb21fcG9pbnQoZGF0YSA9IHBjYSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGZpbGwgPSBwb3AsIGNvbG9yID0gcG9wLCBzaGFwZT15ZWFyKSwgc2l6ZSA9IDEuOCkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGFzdGUwKGNvbHNbYygyLDMsMSldLCI0RCIpLCBndWlkZT0ibm9uZSIpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzW2MoMiwzLDEpXSwgbmFtZT0iUG9wdWxhdGlvbiIpKwogICAgeGxhYihwYXN0ZSgiUEMgMTogIiwgcHJvcF9leHBsYWluZWRbMV0sIiVcbiIsc2VwID0gIiIpKSsKICAgIHlsYWIocGFzdGUoIlBDIDI6ICIsIHByb3BfZXhwbGFpbmVkWzJdLCIlXG4iLHNlcCA9ICIiKSkrCiAgICB0aGVtZV9idygpKwogICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIzLDI1LDMsMjEpLCBuYW1lPSJZZWFyIikKZ2dzYXZlKCIuLi9PdXRwdXQvUENBLzNwb3BfYWxsQ2hyb21vc29tZXMucG5nIiwgaGVpZ2h0ID0gMy44LCB3aWR0aCA9IDUuMiwgZHBpPTMwMCkKCmBgYAohW10oLi4vT3V0cHV0L1BDQS8zcG9wX2FsbENocm9tb3NvbWVzLnBuZykKCgojIyBFYWNoIGNocm9tb3NvbWUgc2VwYXJhdGVseSAgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpQbG90czwtbGlzdCgpCmNocjwtcGFzdGUwKCJjIiwgYygxOjI2KSkKZm9yIChpIGluIDE6bGVuZ3RoKGNocikpewogICAgQyA8LSBhcy5tYXRyaXgocmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvUENBYW5nc2QvM3BvcHNfTUQyMDAwXyIsY2hyW2ldLCIuY292IikpKQogICAgZSA8LSBlaWdlbihDKQogICAgcGNhIDwtZGF0YS5mcmFtZShTYW1wbGU9cG9wMyRTYW1wbGUsIAogICAgICAgICAgICAgICAgICAgICBwb3A9cG9wMyRwb3AsCiAgICAgICAgICAgICAgICAgICAgIHllYXI9cG9wMyR5ZWFyLAogICAgICAgICAgICAgICAgICAgICBQQzE9ZSR2ZWN0b3JzWywxXSxQQzI9ZSR2ZWN0b3JzWywyXSwKICAgICAgICAgICAgICAgICAgICAgUEMzPWUkdmVjdG9yc1ssM10sUEM0PWUkdmVjdG9yc1ssNF0sCiAgICAgICAgICAgICAgICAgICAgIFBDNT1lJHZlY3RvcnNbLDVdLFBDNj1lJHZlY3RvcnNbLDZdLAogICAgICAgICAgICAgICAgICAgICBQQzc9ZSR2ZWN0b3JzWyw3XSxQQzg9ZSR2ZWN0b3JzWyw4XSwKICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKICAgIAogICAgcHJvcF9leHBsYWluZWQgPC0gYygpCiAgICBmb3IgKHMgaW4gZSR2YWx1ZXNbMToxMF0pIHsKICAgICAgICBwcm9wX2V4cGxhaW5lZCA8LSBjKHByb3BfZXhwbGFpbmVkLHJvdW5kKCgocyAvIHN1bShlJHZhbHVlcykpKjEwMCksMikpCiAgICB9CiAgICBQbG90c1tbaV1dPC1nZ3Bsb3QoKSsKICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBwY2EsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBmaWxsID0gcG9wLCBjb2xvciA9IHBvcCwgc2hhcGU9eWVhciksIHNpemUgPSAyLjUpKwogICAgICAgICAgICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXN0ZTAoY29sc1tjKDIsMywxKV0sIjREIiksIGd1aWRlPSJub25lIikrCiAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzW2MoMiwzLDEpXSwgbmFtZT0iUG9wdWxhdGlvbiIpKwogICAgICAgICAgICAgICAgICAgIHhsYWIocGFzdGUoIlBDIDE6ICIsIHByb3BfZXhwbGFpbmVkWzFdLCIlXG4iLHNlcCA9ICIiKSkrCiAgICAgICAgICAgICAgICAgICAgeWxhYihwYXN0ZSgiUEMgMjogIiwgcHJvcF9leHBsYWluZWRbMl0sIiVcbiIsc2VwID0gIiIpKSsKICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpKwogICAgICAgICAgICAgICAgICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMywyNSwzLDIxKSwgbmFtZT0iWWVhciIpKwogICAgICAgICAgICAgICAgICAgIGdndGl0bGUocGFzdGUwKCJDaHIiLGkpKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCn0KZyA8LSBhcnJhbmdlR3JvYihkby5jYWxsKGdyaWQuYXJyYW5nZSwgYyhQbG90cywgbmNvbD01KSkpCmdnc2F2ZShnLCBmaWxlPSIuLi9PdXRwdXQvUENBLzNwb3BzX01EMjAwMF9QQ0FfYnlDaHJvbW9zb21lLnBuZyIsd2lkdGggPSAzNSwgaGVpZ2h0ID0gMzApCgp7cGRmKCIuLi9PdXRwdXQvUENBLzNwb3BzX01EMjAwMF9QQ0FfYnlDaHJvbW9zb21lLnBkZiIsd2lkdGggPSAzMCwgaGVpZ2h0ID0gMzApCmRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKFBsb3RzLCBuY29sPTUpKQpkZXYub2ZmKCkKfQoKIyBQbG90IGxlZ2VuZHMKICAgcDwtZ2dwbG90KCkrCiAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gcGNhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgZmlsbCA9IHBvcCwgY29sb3IgPSBwb3AsIHNoYXBlPXllYXIpLCBzaXplID0gMi41KSsKICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGFzdGUwKGNvbHNbYygyLDMsMSldLCI0RCIpLCBndWlkZT0ibm9uZSIpKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29sc1tjKDIsMywxKV0sIG5hbWU9IlBvcHVsYXRpb24iKSsKICAgICAgICB4bGFiKHBhc3RlKCJQQyAxOiAiLCBwcm9wX2V4cGxhaW5lZFsxXSwiJVxuIixzZXAgPSAiIikpKwogICAgICAgIHlsYWIocGFzdGUoIlBDIDI6ICIsIHByb3BfZXhwbGFpbmVkWzJdLCIlXG4iLHNlcCA9ICIiKSkrCiAgICAgICAgdGhlbWVfYncoKSsKICAgICAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjMsMjUsMywyMSksIG5hbWU9IlllYXIiKSsKICAgICAgICBnZ3RpdGxlKHBhc3RlMCgiQ2hyIixpKSkKCmFzX2dncGxvdChnZXRfbGVnZW5kKHApKQpnZ3NhdmUoIi4uL091dHB1dC9QQ0EvM3BvcHNfTUQyMDAwX1BDQV9ieUNocm9tb3NvbWVfbGVnZW5kLnBuZyIsd2lkdGggPSAxLjUsIGhlaWdodCA9IDUpCgpgYGAKCiFbXSguLi9PdXRwdXQvUENBLzNwb3BzX01EMjAwMF9QQ0FfYnlDaHJvbW9zb21lLnBuZykKCgojIyBDb2xvciBieSBZZWFyICAKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnljb2xzPC1jKCIjZjJmMGY3IiwiI2NiYzllMiIsIiM5ZTlhYzgiLCIjNmE1MWEzIikKClBsb3RzPC1saXN0KCkKY2hyPC1wYXN0ZTAoImMiLCBjKDE6MjYpKQpmb3IgKGkgaW4gMTpsZW5ndGgoY2hyKSl7CiAgICBDIDwtIGFzLm1hdHJpeChyZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9QQ0FhbmdzZC8zcG9wc19NRDIwMDBfIixjaHJbaV0sIi5jb3YiKSkpCiAgICBlIDwtIGVpZ2VuKEMpCiAgICBwY2EgPC1kYXRhLmZyYW1lKFNhbXBsZT1wb3AzJFNhbXBsZSwgCiAgICAgICAgICAgICAgICAgICAgIHBvcD1wb3AzJHBvcCwKICAgICAgICAgICAgICAgICAgICAgeWVhcj1wb3AzJHllYXIsCiAgICAgICAgICAgICAgICAgICAgIFBDMT1lJHZlY3RvcnNbLDFdLFBDMj1lJHZlY3RvcnNbLDJdLAogICAgICAgICAgICAgICAgICAgICBQQzM9ZSR2ZWN0b3JzWywzXSxQQzQ9ZSR2ZWN0b3JzWyw0XSwKICAgICAgICAgICAgICAgICAgICAgUEM1PWUkdmVjdG9yc1ssNV0sUEM2PWUkdmVjdG9yc1ssNl0sCiAgICAgICAgICAgICAgICAgICAgIFBDNz1lJHZlY3RvcnNbLDddLFBDOD1lJHZlY3RvcnNbLDhdLAogICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQogICAgCiAgICBwcm9wX2V4cGxhaW5lZCA8LSBjKCkKICAgIGZvciAocyBpbiBlJHZhbHVlc1sxOjEwXSkgewogICAgICAgIHByb3BfZXhwbGFpbmVkIDwtIGMocHJvcF9leHBsYWluZWQscm91bmQoKChzIC8gc3VtKGUkdmFsdWVzKSkqMTAwKSwyKSkKICAgIH0KICAgIAogICAgUGxvdHNbW2ldXTwtZ2dwbG90KCkrCiAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gcGNhLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgZmlsbCA9IHllYXIsIGNvbG9yID0geWVhciwgc2hhcGU9cG9wKSwgc2l6ZSA9IDIuNSkrCiAgICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXBhc3RlMCh5Y29scywiNEQiKSwgZ3VpZGU9Im5vbmUiKSsKICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXljb2xzLCBuYW1lPSJZZWFyIikrCiAgICAgICAgICAgICAgICAgICAgeGxhYihwYXN0ZSgiUEMgMTogIiwgcHJvcF9leHBsYWluZWRbMV0sIiVcbiIsc2VwID0gIiIpKSsKICAgICAgICAgICAgICAgICAgICB5bGFiKHBhc3RlKCJQQyAyOiAiLCBwcm9wX2V4cGxhaW5lZFsyXSwiJVxuIixzZXAgPSAiIikpKwogICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkrCiAgICAgICAgICAgICAgICAgICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDE2LDE3LDE1KSwgbmFtZT0iUG9wdWxhdGlvbiIpKwogICAgICAgICAgICAgICAgICAgIGdndGl0bGUocGFzdGUwKCJDaHIiLGkpKSt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCn0KCntwZGYoIi4uL091dHB1dC9QQ0EvM3BvcHNfTUQyMDAwX1BDQV9ieUNocm9tb3NvbWVfYnlZZWFyX25vbGVnZW5kcy5wZGYiLHdpZHRoID0gMzAsIGhlaWdodCA9IDMwKQpkby5jYWxsKGdyaWQuYXJyYW5nZSwgYyhQbG90cywgbmNvbD01KSkKZGV2Lm9mZigpCn0KCmcgPC0gYXJyYW5nZUdyb2IoZG8uY2FsbChncmlkLmFycmFuZ2UsIGMoUGxvdHMsIG5jb2w9NCkpKQpnZ3NhdmUoZywgZmlsZT0iLi4vT3V0cHV0L1BDQS8zcG9wc19NRDIwMDBfUENBX2J5Q2hyb21vc29tZV9ieVllYXIucG5nIix3aWR0aCA9IDM1LCBoZWlnaHQgPSA0MCkKCgojIFNhdmUgdGhlIGxlZ2VuZAogICAgcDwtZ2dwbG90KCkrCiAgICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IHBjYSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGZpbGwgPSB5ZWFyLCBjb2xvciA9IHllYXIsIHNoYXBlPXBvcCksIHNpemUgPSAyLjUpKwogICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGFzdGUwKHljb2xzLCI0RCIpLCBndWlkZT0ibm9uZSIpKwogICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXljb2xzLCBuYW1lPSJZZWFyIikrCiAgICAgICAgICAgIHhsYWIocGFzdGUoIlBDIDE6ICIsIHByb3BfZXhwbGFpbmVkWzFdLCIlXG4iLHNlcCA9ICIiKSkrCiAgICAgICAgICAgIHlsYWIocGFzdGUoIlBDIDI6ICIsIHByb3BfZXhwbGFpbmVkWzJdLCIlXG4iLHNlcCA9ICIiKSkrCiAgICAgICAgICAgIHRoZW1lX2J3KCkrCiAgICAgICAgICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxNiwxNywxNSksIG5hbWU9IlBvcHVsYXRpb24iKSsKICAgICAgICAgICAgZ2d0aXRsZShwYXN0ZTAoIkNociIsaSkpCmFzX2dncGxvdChnZXRfbGVnZW5kKHApKQpnZ3NhdmUoIi4uL091dHB1dC9QQ0EvM3BvcHNfTUQyMDAwX1BDQV9ieUNocm9tb3NvbWVfYnlZZWFyX2xlZ2VuZC5wbmciLHdpZHRoID0gMS41LCBoZWlnaHQgPSA1KQoKCmBgYAoKIVtdKC4uL091dHB1dC9QQ0EvM3BvcHNfTUQyMDAwX1BDQV9ieUNocm9tb3NvbWVfYnlZZWFyLnBuZykKCgo8YnI+Cjxicj4KPGJyPgoKIyBQQ0Fuc2dkIFNlbGVjdGlvbiBzY2FuCiMjIEZpbGUgcHJlcHMgYW5kIHJ1bm5pbmcgUENBbmdzZCAgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNEaXZpZGUgdGhlIEJFQUdMRS5QTCBmaWxlIGludG8gZWFjaCBwb3B1bGF0aW9uCgojIEJFQUdMRS5QTC5neiBmaWxlcyBhdmFpbGFibGUgdXBvbiByZXF1ZXN0CmJlYTwtZnJlYWQoIi4uL0RhdGEvdmNmL01EMjAwMC8zcG9wc19NRDIwMDBfcHJ1bmVkX0JFQUdMRS5QTC5neiIpIApwb3BfaW5mbzwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKcG9wX2luZm88LXBvcF9pbmZvWyxjKCJTYW1wbGUiLCJQb3B1bGF0aW9uLlllYXIiLCJwb3AiLCJZZWFyLkNvbGxlY3RlZCIpXQpjb2xuYW1lcyhwb3BfaW5mbylbNF08LSJ5ZWFyIgpwb3BzPC11bmlxdWUocG9wX2luZm8kUG9wdWxhdGlvbi5ZZWFyW2dyZXAoIlBXU3xTU3xUQiIscG9wX2luZm8kUG9wdWxhdGlvbi5ZZWFyKV0pCgoKIyBmb3IgZWFjaCBwb3B1bGF0aW9ucwpwb3BzMzwtYygiUFdTIiwiVEIiLCJTUyIpCmZvciAoaSBpbiAxOmxlbmd0aChwb3BzMykpewogICAgY29sdW1zPC1ncmVwKHBvcHMzW2ldLCBjb2xuYW1lcyhiZWEpKQogICAgdmVjPC1jKDE6MywgY29sdW1zKQogICAgZGY8LWJlYVssLi52ZWNdCiAgICB3cml0ZS50YWJsZShkZiwgZmlsZT1nemZpbGUocGFzdGUwKCIuLi9EYXRhL3ZjZi9NRDIwMDAvIiwgcG9wczNbaV0sIl9NRDIwMDBfcHJ1bmVkLkJFQUdMRS5QTC5neiIpKSwgc2VwPSJcdCIsIHF1b3RlID0gRiwgcm93Lm5hbWVzID0gRkFMU0UgKQp9CgoKCnkxPC1jKCJQV1MwNyIsIlBXUzE3IiwiUFdTOTEiLCJQV1M5NiIpCmNvbWIxPC10KGNvbWJuKHkxLCAyKSkKeTI8LWMoIlRCMDYiLCJUQjE3IiwiVEI5MSIsIlRCOTYiKQpjb21iMjwtdChjb21ibih5MiwgMikpCnkzPC1jKCJTUzA2IiwiU1MxNyIsIlNTOTYiKQpjb21iMzwtdChjb21ibih5MywgMikpCmNvbWI0PC1kYXRhLmZyYW1lKFYxPWMoIlBXUzA3IiwiUFdTMTciLCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIsIlBXUzk2IiwiU1MwNiIsIlNTMTciLCJTUzk2IiksIFYyPWMoIlRCMDYiLCJUQjE3IiwiVEI5MSIsIlRCOTYiLCJTUzA2IiwiU1MxNyIsIlNTOTYiLCJUQjA2IiwiVEIxNyIsIlRCOTYiKSkKY29tYjwtcmJpbmQoY29tYjEsY29tYjIsY29tYjMsIGNvbWI0KQoKZm9yIChpIGluIDM6bnJvdyhjb21iKSl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgY29sMTwtZ3JlcChwb3AxLCBjb2xuYW1lcyhiZWEpKQogICAgY29sMjwtZ3JlcChwb3AyLCBjb2xuYW1lcyhiZWEpKQogICAgdmVjPC1jKDE6MywgY29sMSwgY29sMikKICAgIGRmPC1iZWFbLC4udmVjXQogICAgd3JpdGUudGFibGUoZGYsIGZpbGU9Z3pmaWxlKHBhc3RlMCgiLi4vRGF0YS92Y2YvTUQyMDAwLyIsIHBvcDEsIl8iLHBvcDIsIl9NRDIwMDBfcHJ1bmVkLkJFQUdMRS5QTC5neiIpKSwgc2VwPSJcdCIsIHF1b3RlID0gRiwgcm93Lm5hbWVzID0gRkFMU0UgKQp9CgoKIyBDcmVhdGUgc2x1cm0gc2NyaXB0cwpiZmlsZXM8LWxpc3QuZmlsZXMoIi4uL0RhdGEvbmV3X3ZjZi9NRDIwMDAvIiwgcGF0dGVybj0iQkVBR0xFLlBMLmd6IikKCnNpbmsoIi4uL0RhdGEvU2x1cm1zY3JpcHRzL3BjYW5zZ2Rfc2VsZWN0aW9uX21kMjAwMC5zaCIpCmNhdCgiIyEvYmluL2Jhc2ggLWwiKQpjYXQoIlxuIikKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWpvYi1uYW1lPXNlbGVjdGlvbiBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tbWVtPTI0RyBcbiIpKSAKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW50YXNrcz04IFxuIikpIApjYXQocGFzdGUwKCIjU0JBVENIIC0tbm9kZXM9NCAgXG4iKSkgCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLWUgc2VsZWN0aW9uLmVyciAgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLXRpbWU9MTQ0OjAwOjAwICBcbiIpKQojY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW1haWwtdXNlcj1rdGlzdEB1Y2RhdmlzLmVkdSAjI2VtYWlsIHlvdSB3aGVuIGpvYiBzdGFydHMsZW5kcyxldGMgXG4iKSkKI2NhdChwYXN0ZTAoIiNTQkFUQ0ggLS1tYWlsLXR5cGU9QUxMIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLXAgaGlnaCAgXG4iKSkKY2F0KCJcbiIpCmNhdCgibW9kdWxlIGxvYWQgYW5nc2QKbW9kdWxlIGxvYWQgZGVwcmVjYXRlZC9weXRob24KbW9kdWxlIGxvYWQgZGVwcmVjYXRlZC9wY2FuZ3NkIikKY2F0KCJcblxuIikKCmZvciAoaSBpbiAxOmxlbmd0aChiZmlsZXMpKXsKICBmbmFtZTwtZ3N1YigiX01EMjAwMF9wcnVuZWQuQkVBR0xFLlBMLmd6IiwnJywgYmZpbGVzW2ldKQogIGNhdChwYXN0ZTAoInB5dGhvbiAvaG9tZS9qYW1jZ2lyci9hcHBzL3BjYW5nc2QvcGNhbmdzZC5weSAtYmVhZ2xlIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDMwMDAvYmVhZ2xlLyIsYmZpbGVzW2ldLCIgLW8gL2hvbWUva3Rpc3QvcGgvZGF0YS9hbmdzZC9zZWxlY3Rpb24vIixmbmFtZSwiX3NlbGVjdGlvbiAtc2VsZWN0aW9uIC1zaXRlc19zYXZlIFxuIikpCn0KCnNpbmsoTlVMTCkKCiMocmFuIHBjYW5zZ2Rfc2VsZWN0aW9uX21kMjAwMC5zaCwgcGNhbnNnZF9zZWxlY3Rpb25fbWQyMDAwXzEuc2gsIHBjYW5zZ2Rfc2VsZWN0aW9uX21kMjAwMF8yLnNoIGF0IEZhcm0gb24gNi8yOC8yMykKYGBgCgoKIyMgUGxvdCB0aGUgcmVzdWx0cyBvZiBlYWNoIHBvcHVsYXRpb24gCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgU2VsZWN0aW9uIHNjYW4gcmVzdWx0cyBhcmUgYXZhaWxhYmxlIGF0OiBPU0YgU3RvcmFnZTogaHR0cHM6Ly9vc2YuaW8vd3JjYTQgRGF0YS9QQ0FuZ3NkL3NlbGVjdGlvbi8KCnBvcF9pbmZvPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpwb3BfaW5mbzwtcG9wX2luZm9bLGMoIlNhbXBsZSIsInBvcCIsIlllYXIuQ29sbGVjdGVkIildCmNvbG5hbWVzKHBvcF9pbmZvKVszXTwtInllYXIiCgoKIyMjIyMjIwojIyMgU2VsZWN0aW9uICMjIwpsaWJyYXJ5KFJjcHBDTlB5KSAjIE51bXB5IGxpYnJhcnkgZm9yIFIKCiMjIGZ1bmN0aW9uIGZvciBRUXBsb3QKcXFjaGk8LWZ1bmN0aW9uKHgsLi4uKXsKICAgIGxhbWJkYTwtcm91bmQobWVkaWFuKHgpL3FjaGlzcSgwLjUsMSksMikKICAgIHFxcGxvdChxY2hpc3EoKDE6bGVuZ3RoKHgpLTAuNSkvKGxlbmd0aCh4KSksMSkseCx5bGFiPSJPYnNlcnZlZCIseGxhYj0iRXhwZWN0ZWQiLC4uLik7YWJsaW5lKDAsMSxjb2w9Mixsd2Q9MikKICAgIGxlZ2VuZCgidG9wbGVmdCIscGFzdGUoImxhbWJkYT0iLGxhbWJkYSkpCn0KCiMjIyByZWFkIGluIHNlbGVjaXRvbiBzdGF0aXN0aWNzIChjaGkyIGRpc3RyaWJ1dGVkKQojIEVhY2ggY29sdW1uIHJlZmxlY3QgdGhlIHNlbGVjdGlvbiBzdGF0aXN0aWNzIGFsb25nIGEgdGVzdGVkIFBDICh0aGV5IGFyZSDPh8KyLWRpc3RyaWJ1dGVkIHdpdGggMSBkZWdyZWUgb2YgZnJlZWRvbS4pCnM8LW5weUxvYWQoIi4uL0RhdGEvUENBYW5nc2Qvc2VsZWN0aW9uL1BXU19zZWxlY3Rpb24uc2VsZWN0aW9uLm5weSIpCgojIyBtYWtlIFFRIHBsb3QgdG8gUUMgdGhlIHRlc3Qgc3RhdGlzdGljcwpxcWNoaShzKQpuY29sKHMpCgojIyByZWFkIHBvc2l0aW9ucyAKcDwtcmVhZC50YWJsZSgiLi4vRGF0YS9QQ0FhbmdzZC9zZWxlY3Rpb24vUFdTX3NlbGVjdGlvbi5zaXRlcyIsY29sQz1jKCJmYWN0b3IiLCJpbnRlZ2VyIiksc2VwPSI6IikKbmFtZXMocCk8LWMoImNociIsInBvcyIpCgoKIyAxLiAxIGF4aXM6CiNjb252ZXJ0IHRlc3Qgc3RhdGlzdGljIHRvIHAtdmFsdWUKcCRwdmFsPC0xLXBjaGlzcShzLDEpCnAkbG9jPC0xOm5yb3cocCkKcCRwdmFsLmxvZzwtLWxvZzEwKHAkcHZhbCkKCiMjIG1ha2UgbWFuaGF0dGVuIHBsb3QKcGxvdCgtbG9nMTAocCRwdmFsKSxjb2w9cCRjaHIseGxhYj0iQ2hyb21vc29tZXMiLG1haW49Ik1hbmhhdHRhbiBwbG90IiwgcGNoPSIuIikKCiMgMi4gaWYgbW9yZSB0aGFuIDEgYXhpcyAobmNvbChzKT4xKQojIHAkcHZhbDE8LXB2YWxbLDFdCiMgcCRwdmFsMjwtcHZhbFssMl0KIyBwJGxvYzwtMTpucm93KHApCiMgcCRwdmFsMS5sb2c8LS1sb2cxMChwJHB2YWwxKQojIHAkcHZhbDIubG9nPC0tbG9nMTAocCRwdmFsMikKCiMjIG1ha2UgTWFuaGF0dGFuIHBsb3RzCnBvcHMxPC1jKCJQV1MiLCJTUyIsIlRCIikKZXZlbnM8LXBhc3RlMCgiY2hyIixzZXEoMiwyNiwgYnk9MikpCgpmb3IgKGkgaW4gMTpsZW5ndGgocG9wczEpKXsKICAgIHM8LW5weUxvYWQocGFzdGUwKCIuLi9EYXRhL1BDQWFuZ3NkL3NlbGVjdGlvbi8iLHBvcHMxW2ldLCJfc2VsZWN0aW9uLnNlbGVjdGlvbi5ucHkiKSkKICAgIHA8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL1BDQWFuZ3NkL3NlbGVjdGlvbi8iLHBvcHMxW2ldLCJfc2VsZWN0aW9uLnNpdGVzIiksY29sQz1jKCJmYWN0b3IiLCJpbnRlZ2VyIiksc2VwPSI6IikKICAgIG5hbWVzKHApPC1jKCJjaHIiLCJwb3MiKQoKICAgIG48LW5jb2wocykKICAgIGlmIChuPT0xKXsKICAgICAgICBwJHB2YWw8LTEtcGNoaXNxKHMsMSkKICAgICAgICBwJGxvYzwtMTpucm93KHApCiAgICAgICAgcCRwdmFsLmxvZzwtLWxvZzEwKHAkcHZhbCkKICAgIH0KICAgICNjb3VudCB0aGUgbnVtYmVyIG9mIHNpdGVzIHBlciBjaHJvbW9zb21lcwogICAgcG9zczwtZGF0YS5mcmFtZShjaHI9cGFzdGUwKCJjaHIiLDE6MjYpKQogICAgaz0xCiAgICBmb3IgKGogaW4gMToyNil7CiAgICAgICAgZGY8LXBbcCRjaHI9PXBhc3RlMCgiY2hyIixqKSxdCiAgICAgICAgcG9zcyRzdGFydFtqXTwtawogICAgICAgIHBvc3MkZW5kW2pdPC1rK25yb3coZGYpLTEKICAgICAgICBrPWsrbnJvdyhkZikKICAgIH0KICAgIHBvc3MkeDwtcG9zcyRzdGFydCsocG9zcyRlbmQtcG9zcyRzdGFydCkvMgoKICAgIHAkY29sb3I8LSJzdGVlbGJsdWUiCiAgICBwJGNvbG9yW3AkY2hyICVpbiUgZXZlbnNdPC0ibGlnaHRibHVlIgogICAgZ2dwbG90KGRhdGE9cCwgYWVzKHg9bG9jLCB5PXB2YWwubG9nLCBjb2xvcj1jb2xvcikpKwogICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjEpKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygibGlnaHRibHVlIiwic3RlZWxibHVlIiksIGd1aWRlPSdub25lJykrCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKG5hbWU9IkNocm9tb3NvbWUgcG9zaXRpb24iLCBicmVha3M9cG9zcyR4LCBsYWJlbHM9MToyNikrCiAgICAgICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIi1sb2cxMChwLXZhbHVlKSIpKwogICAgICAgIGdndGl0bGUocG9wczFbaV0pCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUENBL3NlbGVjdGlvbl9NRDIwMDAvIixwb3BzMVtpXSwiX3NlbGVjdGlvbl9zY2FuLnBuZyIpLCB3aWR0aD04LCBoZWlnaHQ9NCxkcGk9MzAwKQogICAgICAgICAgIAp9CgojIC1sb2cxMCgwLjA1KSA9IDEuMzAxMDMKIyAtbG9nMTAoMC4wNS8yMzI2NDQpICM2LjY2NzcyMgojIyMgIFNpZ25pZmljYW50IHAtdmFsdWUgZm9yIDIzMiw2NDQgbG9jaSBpcyA2LjY3ICAjIyMKCgoKYGBgCgohW10oLi4vT3V0cHV0L1BDQS9zZWxlY3Rpb25fTUQyMDAwL1BXU19zZWxlY3Rpb25fc2Nhbi5wbmcpCiFbXSguLi9PdXRwdXQvUENBL3NlbGVjdGlvbl9NRDIwMDAvVEJfc2VsZWN0aW9uX3NjYW4ucG5nKQoKIVtdKC4uL091dHB1dC9QQ0Evc2VsZWN0aW9uX01EMjAwMC9TU19zZWxlY3Rpb25fc2Nhbi5wbmcpCgoqIE5PIHNpdGVzIGFib3ZlIDYuNwoKIyMgUGxvdCByZXN1bHRzIG9mIHBhcml3aXNlIGNvbXBhcmlzb24KYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KeTE8LWMoIlBXUzA3IiwiUFdTMTciLCJQV1M5MSIsIlBXUzk2IikKY29tYjE8LXQoY29tYm4oeTEsIDIpKQp5MjwtYygiVEIwNiIsIlRCMTciLCJUQjkxIiwiVEI5NiIpCmNvbWIyPC10KGNvbWJuKHkyLCAyKSkKeTM8LWMoIlNTMDYiLCJTUzE3IiwiU1M5NiIpCmNvbWIzPC10KGNvbWJuKHkzLCAyKSkKY29tYjwtcmJpbmQoY29tYjEsIGNvbWIyLCBjb21iMykKCmV2ZW5zPC1wYXN0ZTAoImNociIsc2VxKDIsMjYsIGJ5PTIpKQoKZm9yIChpIGluIDE6bnJvdyhjb21iKSl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgczwtbnB5TG9hZChwYXN0ZTAoIi4uL0RhdGEvUENBYW5nc2Qvc2VsZWN0aW9uLyIscG9wMSwgIl8iLHBvcDIsIl9zZWxlY3Rpb24uc2VsZWN0aW9uLm5weSIpKQogICAgcDwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvUENBYW5nc2Qvc2VsZWN0aW9uLyIscG9wMSwgIl8iLHBvcDIsIl9zZWxlY3Rpb24uc2l0ZXMiKSxjb2xDPWMoImZhY3RvciIsImludGVnZXIiKSxzZXA9IjoiKQogICAgbmFtZXMocCk8LWMoImNociIsInBvcyIpCgogICAgbjwtbmNvbChzKQogICAgaWYgKG49PTEpewogICAgICAgIHAkcHZhbDwtMS1wY2hpc3EocywxKQogICAgICAgIHAkbG9jPC0xOm5yb3cocCkKICAgICAgICBwJHB2YWwubG9nPC0tbG9nMTAocCRwdmFsKQogICAgfQogICAgaWYgKG4+MSl7CiAgICAgICAgcCRwdmFsPC1wdmFsWywxXQogICAgICAgIHAkbG9jPC0xOm5yb3cocCkKICAgICAgICBwJHB2YWwubG9nPC0tbG9nMTAocCRwdmFsKQogICAgfQogICAgI2NvdW50IHRoZSBudW1iZXIgb2Ygc2l0ZXMgcGVyIGNocm9tb3NvbWVzCiAgICBwb3NzPC1kYXRhLmZyYW1lKGNocj1wYXN0ZTAoImNociIsMToyNikpCiAgICBrPTEKICAgIGZvciAoaiBpbiAxOjI2KXsKICAgICAgICBkZjwtcFtwJGNocj09cGFzdGUwKCJjaHIiLGopLF0KICAgICAgICBwb3NzJHN0YXJ0W2pdPC1rCiAgICAgICAgcG9zcyRlbmRbal08LWsrbnJvdyhkZiktMQogICAgICAgIGs9aytucm93KGRmKQogICAgfQogICAgcG9zcyR4PC1wb3NzJHN0YXJ0Kyhwb3NzJGVuZC1wb3NzJHN0YXJ0KS8yCgogICAgcCRjb2xvcjwtInN0ZWVsYmx1ZSIKICAgIHAkY29sb3JbcCRjaHIgJWluJSBldmVuc108LSJsaWdodGJsdWUiCiAgICBnZ3Bsb3QoZGF0YT1wLCBhZXMoeD1sb2MsIHk9cHZhbC5sb2csIGNvbG9yPWNvbG9yKSkrCiAgICAgICAgZ2VvbV9wb2ludChzaXplPTAuMSkrCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJsaWdodGJsdWUiLCJzdGVlbGJsdWUiKSwgZ3VpZGU9J25vbmUnKSsKICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZT0iQ2hyb21vc29tZSBwb3NpdGlvbiIsIGJyZWFrcz1wb3NzJHgsIGxhYmVscz0xOjI2KSsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkreWxhYigiLWxvZzEwKHAtdmFsdWUpIikrCiAgICAgICAgZ2d0aXRsZShwYXN0ZTAocG9wMSwgIiAtICIsIHBvcDIpKQogICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1BDQS9zZWxlY3Rpb25fTUQyMDAwLyIscG9wMSwgIl8iLHBvcDIsIl9zZWxlY3Rpb25fc2Nhbi5wbmciKSwgd2lkdGg9OCwgaGVpZ2h0PTQsZHBpPTMwMCkKfQpgYGAKIVtdKC4uL091dHB1dC9QQ0Evc2VsZWN0aW9uX01EMjAwMC9QV1M5MV9QV1M5Nl9zZWxlY3Rpb25fc2Nhbi5wbmcpCgoKIVtdKC4uL091dHB1dC9QQ0Evc2VsZWN0aW9uX01EMjAwMC9QV1MwN19QV1M5Nl9zZWxlY3Rpb25fc2Nhbi5wbmcpCiFbXSguLi9PdXRwdXQvUENBL3NlbGVjdGlvbl9NRDIwMDAvUFdTMDdfUFdTMTdfc2VsZWN0aW9uX3NjYW4ucG5nKQohW10oLi4vT3V0cHV0L1BDQS9zZWxlY3Rpb25fTUQyMDAwL1RCOTFfVEI5Nl9zZWxlY3Rpb25fc2Nhbi5wbmcpCgohW10oLi4vT3V0cHV0L1BDQS9zZWxlY3Rpb25fTUQyMDAwL1RCMDZfVEI5Nl9zZWxlY3Rpb25fc2Nhbi5wbmcpCiFbXSguLi9PdXRwdXQvUENBL3NlbGVjdGlvbl9NRDIwMDAvVEIwNl9UQjE3X3NlbGVjdGlvbl9zY2FuLnBuZykKCiFbXSguLi9PdXRwdXQvUENBL3NlbGVjdGlvbl9NRDIwMDAvU1MwNl9TUzk2X3NlbGVjdGlvbl9zY2FuLnBuZykKIVtdKC4uL091dHB1dC9QQ0Evc2VsZWN0aW9uX01EMjAwMC9TUzA2X1NTMTdfc2VsZWN0aW9uX3NjYW4ucG5nKQoKPGJyPgo8YnI+Cjxicj4KCiMgTkdTYWRtaXgKCiMjIFJ1biBOR1NhZG1peCAoYXQgRmFybSBvciBsb2NhbGx5KQoqIE5HU2FkbWl4X21kMjAwMF8xLnNoLE5HU2FkbWl4X21kMjAwMF8yLnNoLE5HU2FkbWl4X21kMjAwMF8zLnNoCgoKIyMgUnVuIENMVU1QQUwgdG8gZmluZCBiZXN0IEsKKiAoVGhlIGJlc3QgSyA9MykKCiMjIyBDb21waWxlIGFsbCBsaWtlbGlob29kIG51bWJlcnMgZnJvbSBsb2cgZmlsZXMgaW50byAxIChsb2dmaWxlKQoKYGBge2Jhc2ggZXZhbD1GQUxTRX0KI2xpbnV4IGNvZGUgKHdvbid0IHdvcmsgd2l0aCB1bml4KQooZm9yIGxvZyBpbiBgbHMgKi5sb2dgOyBkbyBncmVwIC1vUCAnM3BvcHNfcHJ1bmVkX21hZjA1X1xLW14gXSt8bGlrZT1cS1teIF0rJyAkbG9nOyBkb25lKSA+IDNwb3BzX2xvZ2ZpbGVfazMKKGZvciBsb2cgaW4gYGxzICoubG9nYDsgZG8gZ3JlcCAtb1AgJzNwcHNfcHJ1bmVkX21hZjA1X1xLW14gXSt8bGlrZT1cS1teIF0rJyAkbG9nOyBkb25lKSA+IDNwb3BzX2xvZ2ZpbGVfazIKKGZvciBsb2cgaW4gYGxzICoubG9nYDsgZG8gZ3JlcCAtb1AgJzNwb3BzX3BydW5lZF9tYWYwNV9cS1teIF0rfGxpa2U9XEtbXiBdKycgJGxvZzsgZG9uZSkgPiAzcG9wc19sb2dmaWxlX2s0CmBgYAoKIyMgUmVhZCAnbG9nZmlsZScgJiBjcmVhdGUgYW4gaW5wdXQgZmlsZSBmb3IgQ2x1bXBhawoqIGh0dHA6Ly9jbHVtcGFrLnRhdS5hYy5pbC9iZXN0Sy5odG1sICAKKiBVcGxvYWQgdGhlIGxvZyBwcm9iYWJpbGl0eSB0YWJsZSBmaWxlIHRvIHRoZSB3ZWJzaXRlIGFuZCBzdWJtaXQgdGhlIGZvcm0KCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxvZzI8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvM3BvcHNfbG9nZmlsZV9rMiIsIHNlcD0iXHQiLCBoZWFkZXIgPUZBTFNFKQpsb2czPC1yZWFkLnRhYmxlKCIuLi9EYXRhL25nc2FkbWl4LzNwb3BzX2xvZ2ZpbGVfazMiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKbG9nNDwtcmVhZC50YWJsZSgiLi4vRGF0YS9uZ3NhZG1peC8zcG9wc19sb2dmaWxlX2s0Iiwgc2VwPSJcdCIsIGhlYWRlciA9RkFMU0UpCmxvZzQ8LWRhdGEuZnJhbWUobG9nNFtjKEZBTFNFLFRSVUUpLF0pCgpsb2dzPC1kYXRhLmZyYW1lKEs9YyhyZXAoMiwgdGltZXM9MTApLHJlcCgzLCB0aW1lcz0xMCkscmVwKDQsIHRpbWVzPTEwKSksIExpa2xpaG9vZD1jKGxvZzIkVjEsbG9nMyRWMSwgbG9nNCkpCndyaXRlLnRhYmxlKGxvZ3MsICIuLi9PdXRwdXQvbmdzYWRtaXgvM3BvcHNsb2dzLnR4dCIsIHNlcD0iXHQiLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLCBxdW90ZT1GKQojIERPIE5PVCB1c2Ugc3BlY2lhbCBjaGFyYWN0ZXIgaW4gdGhlIGZpbGUgbmFtZQojIE11c3QgaGF2ZSBhdCBsZWFzdCB0aHJlZSBLIHZhbHVlcwoKIyB1cGxvYWQgdGhlIGxvZ3MudHh0IHRvIENsdW1wYWsgd2Vic2l0ZQojIGh0dHA6Ly9jbHVtcGFrLnRhdS5hYy5pbAoKIydFc3RpbWF0aW5nIHRoZSBCZXN0IEsgKGZyb20gQ2x1bXBhayknCiNXZWQgSnVsICA1IDIwOjE1OjUyIDIwMjM6IExuJygzKSA9IDI3NzMzNi42MjIzOTU4OTUKI1dlZCBKdWwgIDUgMjA6MTU6NTIgMjAyMzogTG4nKDQpID0gMjY0MzIyLjAzMDYyNTE5NAojV2VkIEp1bCAgNSAyMDoxNTo1MiAyMDIzOiB8TG4nJyhLPTMpfCA9IDEzMDE0LjU5MTc3MDcwMTEKI1dlZCBKdWwgIDUgMjA6MTU6NTIgMjAyMzogRGVsdGEoSz0zKSA9IDEzMC4wODU2NzE2ODg3NDEKI1dlZCBKdWwgIDUgMjA6MTU6NTIgMjAyMzogTWF4IERlbHRhIEs6IDEzMC4wODU2NzE2ODg3NDEKI1dlZCBKdWwgIDUgMjA6MTU6NTIgMjAyMzogT3B0aW1hbCBLIGJ5IEV2YW5ubyBpczogMwojV2VkIEp1bCAgNSAyMDoxNTo1NiAyMDIzOiBVc2luZyBtZWRpYW4gdmFsdWVzIG9mIExuIFByb2Igb2YgRGF0YSB0byBjYWxjdWxhdGUgUHJvYihLPWspOgojV2VkIEp1bCAgNSAyMDoxNTo1NiAyMDIzOiBQcm9iKEs9MikgPSAwCiNXZWQgSnVsICA1IDIwOjE1OjU2IDIwMjM6IFByb2IoSz0zKSA9IDAKI1dlZCBKdWwgIDUgMjA6MTU6NTYgMjAyMzogUHJvYihLPTQpID0gMQojV2VkIEp1bCAgNSAyMDoxNTo1NiAyMDIzOiBNYXggUHJvYmFiaWxpdHk6IDEKI1dlZCBKdWwgIDUgMjA6MTU6NTYgMjAyMzogVGhlIGsgZm9yIHdoaWNoIFByb2IoSz1rKSBvYnRhaW5zIHRoZSBoaWdoZXN0IHZhbHVlIGlzOiA0CiMKIwojCmBgYAohW10oLi4vT3V0cHV0L25nc2FkbWl4L2NsdW1wYWtfcmVzdWx0cy9CZXN0X0tfQnlfRXZhbm5vLURlbHRhS0J5S0dyYXBoLnBuZykKCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvY2x1bXBha19yZXN1bHRzL0Jlc3RfS19CeV9Qcml0Y2hhcmQtUHJvYkJ5S0dyYXBoLnBuZykKCiogMiBtYWtlcyBtb3JlIHNlbnNlIHRoYW4gMyBidXQgdGhlIHJldXNsdHMgY2hvc2UgIks9MyIgYXMgdGhlIGJlc3QKCgojIyBSdW4gZXZhbEFkbWl4CmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojQ3JlYXRlIGJhc2ggc2NyaXB0cyB0byBydW4gbG9jYWxseQpzaW5rKCIuLi9EYXRhL1NsdXJtc2NyaXB0cy9ldmFsQWRtaXhfcnVubG9jYWwuc2giKQpjYXQoIiMhL2Jpbi9iYXNoXG5cbiIpCgpmb3IgKGkgaW4gMjozKXsKICAgIGNhdCgiZXZhbEFkbWl4IC1iZWFnbGUgRGF0YS9uZXdfdmNmL01EMjAwMC9iZWFnbGUvM3BvcHNfTUQyMDAwX3BydW5lZF9CRUFHTEUuUEwuZ3ogIikKICAgIGNhdChwYXN0ZTAoIi1mbmFtZSBEYXRhL25nc2FkbWl4LzNwb3BzX3BydW5lZF9tYWYwNV9rIixpLCJfcnVuMS5mb3B0Lmd6ICIpKQogICAgY2F0KHBhc3RlMCgiLXFuYW1lIERhdGEvbmdzYWRtaXgvM3BvcHNfcHJ1bmVkX21hZjA1X2siLGksIl9ydW4xLnFvcHQgIikpCiAgICBjYXQoIi1QIDEwICIpCiAgICBjYXQocGFzdGUwKCItbyBEYXRhL25nc2FkbWl4L2V2YWxhZG1peC9vdXRwdXQuY29ycmVzLmsiLGksIi50eHRcbiIpKQp9CnNpbmsoTlVMTCkKCmBgYAoKCiMgUGxvdCByZXN1bHRzCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzb3VyY2UoInZpc0Z1bnMuUiIpCgojT3V0cHV0IGZpbGVzCnFmaWxlczwtbGlzdC5maWxlcygiLi4vRGF0YS9uZ3NhZG1peC8iLHBhdHRlcm49Il9ydW4xLnFvcHQiKQpvZmlsZXM8LWxpc3QuZmlsZXMoIi4uL0RhdGEvbmdzYWRtaXgvZXZhbGFkbWl4LyIscGF0dGVybj0ib3V0cHV0LmNvcnJlcyIpCgojcG9wdWxhdGlvbiBpbmZvCnBvcDwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKcG9wPC1wb3BbZ3JlcCgiUFdTfFNTfFRCIiwgcG9wJHBvcCksXQpwb3AkUG9wdWxhdGlvbi5ZZWFyPC1mYWN0b3IocG9wJFBvcHVsYXRpb24uWWVhciwgbGV2ZWxzPWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciLCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIsIlNTOTYiLCJTUzA2IiwiU1MxNyIpKQpwb3BvcmRlcjwtcGFzdGUocG9wJFBvcHVsYXRpb24uWWVhcltvcmRlcihwb3AkUG9wdWxhdGlvbi5ZZWFyKV0pCnBvcF9vcmRlcjwtYygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIsIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IikKCmZvciAoaSBpbiAxOmxlbmd0aChxZmlsZXMpKXsKICAgICMgZXh0cmFjdCBLIGZyb20gdGhlIGZpbGUgbmFtZQogICAgaWYgKGkhPTMpIHsKICAgICAgICBvbmFtZTwtb2ZpbGVzW2ldCiAgICAgICAgazwtZ3N1YigiW14wLTkuXSIsICIiLCBvZmlsZXNbaV0pCiAgICAgICAgazwtYXMuaW50ZWdlcihnc3ViKCJcXC4iLCcnLGspKQogICAgfQogICAgaWYgKGk9PTMpIGs9MwogICAgCiAgICAjcmVhZCB0aGUgcW9wdCBmaWxlIGZvciBrPWsKICAgIHE8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL25nc2FkbWl4LyIsIHFmaWxlc1tpXSkpCiAgICAKICAgICNvcmRlciBhY2NvcmRpbmcgdG8gcG9wdWxhdGlvbiBhbmQgcGxvdCB0aGUgTkdTYWRtaXggcmVzdWx0cwogICAgcSRpZDwtcG9wJFBvcHVsYXRpb24uWWVhcgogICAgcTwtcVtvcmRlcihxJGlkKSxdCiAgICAKICAgIG9yZDwtb3JkZXJJbmRzKHBvcCA9IGFzLnZlY3Rvcihwb3BvcmRlciksIHEgPSBxWywxOihpKzEpXSkKICAgIAogICAgeGxhYmVsczwtZGF0YS5mcmFtZSh4PXRhcHBseSgxOmxlbmd0aChwb3BvcmRlciksbGlzdChwb3BvcmRlciksIG1lYW4pKQogICAgeGxhYmVscyRwb3A8LWZhY3Rvcihyb3duYW1lcyh4bGFiZWxzKSwgbGV2ZWxzPXBvcF9vcmRlcikKICAgIHhsYWJlbHM8LXhsYWJlbHNbb3JkZXIoeGxhYmVscyRwb3ApLF0KICAgIAogICAgI2NvbG9yIGFzc2lnbm1lbnQKICAgIGlmIChpPT0xKSBjb2xvcnM9Y29sc1tjKDEsMildCiAgICBpZiAoaT09MikgY29sb3JzPWNvbHNbYygxLDYsMikgXQogICAgaWYgKGk9PTMpIGNvbG9ycz1jb2xzW2MoMSw2LDIsMykgXQoKICAgIHtwbmcocGFzdGUwKCIuLi9PdXRwdXQvbmdzYWRtaXgvM3BvcHNfQWRtaXhfcGxvdF9rIixrLCIucG5nIiksIGhlaWdodCA9IDMuNSwgd2lkdGg9OCwgdW5pdD0iaW4iLCByZXM9MzAwKQogICAgYmFycGxvdCh0KHFbLDE6KGkrMildKVssb3JkXSxjb2w9Y29sb3JzLHNwYWNlPTAsYm9yZGVyPU5BLHhheHQ9Im4iLHhsYWI9IiIseWxhYj1wYXN0ZTAoIkFkbWl4dHVyZSBwcm9wb3J0aW9ucyBmb3IgSz0iLGspKQogICAgdGV4dCh4bGFiZWxzJHgsLTAuMDUseGxhYmVscyRwb3AseHBkPVQsIHNydD05MCwgYWRqPTEsY2V4PTAuOCkKICAgIGFibGluZSh2PWN1bXN1bShzYXBwbHkodW5pcXVlKHBvcG9yZGVyW29yZF0pLGZ1bmN0aW9uKHgpe3N1bShwb3Bbb3JkLCJQb3B1bGF0aW9uLlllYXIiXT09eCl9KSksY29sPTEsbHdkPTEuMikKICAgIGRldi5vZmYoKX0KICAgIAogICAgI1Bsb3QgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBmcm9tIGV2YWxBZG1peAogICAgaWYgKGkhPTMpIHsKICAgICAgICByPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9uZ3NhZG1peC9ldmFsYWRtaXgvIixvZmlsZXNbaV0pKQogICAgCiAgICAjIFBsb3QgY29ycmVsYXRpb24gb2YgcmVzaWR1YWxzCiAgICB7cGRmKHBhc3RlMCgiLi4vT3V0cHV0L25nc2FkbWl4LzNwb3BzX2V2YWxBZG1peF9jb3JwbG90X2siLGssIi5wZGYiKSwgaGVpZ2h0ID0gOCwgd2lkdGg9MTApCiAgICBwbG90Q29yUmVzKGNvcl9tYXQgPSByLCBwb3AgPSBhcy52ZWN0b3IocG9wWywiUG9wdWxhdGlvbi5ZZWFyIl0pLCBvcmQgPSBvcmQsIHRpdGxlPXBhc3RlMCgiRXZhbHVhdGlvbiBvZiBhZG1peHR1cmUgcHJvcG9ydGlvbnMgd2l0aCBLPSIsayksIG1heF96PTAuMSwgbWluX3o9LTAuMSkKICAgIGRldi5vZmYoKX0KICAgIH0KfQpgYGAKIVtdKC4uL091dHB1dC9uZ3NhZG1peC8zcG9wc19BZG1peF9wbG90X2syLnBuZykKCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvM3BvcHNfZXZhbEFkbWl4X2NvcnBsb3RfazIucG5nKQoKCgohW10oLi4vT3V0cHV0L25nc2FkbWl4LzNwb3BzX0FkbWl4X3Bsb3RfazMucG5nKQoKIVtdKC4uL091dHB1dC9uZ3NhZG1peC8zcG9wc19ldmFsQWRtaXhfY29ycGxvdF9rMy5wbmcpCgoKCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIHBsb3QgYWxsIDEwIHJlcGxpY2F0ZXMgZm9yIGs9MwpxZmlsZXM8LWxpc3QuZmlsZXMoIi4uL0RhdGEvbmdzYWRtaXgvIixwYXR0ZXJuPSJeM3BvcHNfcHJ1bmVkX21hZjA1X2szKy4qLnFvcHQiKQpmb3IgKGkgaW4gMjoxMCl7CiAgICBxPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9uZ3NhZG1peC8iLCBxZmlsZXNbaV0pKQogICAgCiAgICAjb3JkZXIgYWNjb3JkaW5nIHRvIHBvcHVsYXRpb24gYW5kIHBsb3QgdGhlIE5HU2FkbWl4IHJlc3VsdHMKICAgIHEkaWQ8LXBvcCRQb3B1bGF0aW9uLlllYXIKICAgIHE8LXFbb3JkZXIocSRpZCksXQogICAgCiAgICBvcmQ8LW9yZGVySW5kcyhwb3AgPSBhcy52ZWN0b3IocG9wb3JkZXIpLCBxID0gcVssMTozXSkKICAgIAogICAgeGxhYmVsczwtZGF0YS5mcmFtZSh4PXRhcHBseSgxOmxlbmd0aChwb3BvcmRlciksbGlzdChwb3BvcmRlciksIG1lYW4pKQogICAgeGxhYmVscyRwb3A8LWZhY3Rvcihyb3duYW1lcyh4bGFiZWxzKSwgbGV2ZWxzPXBvcF9vcmRlcikKICAgIHhsYWJlbHM8LXhsYWJlbHNbb3JkZXIoeGxhYmVscyRwb3ApLF0KICAgIAogICAgI2NvbG9yIGFzc2lnbm1lbnQKICAgIGNvbG9ycz1jb2xzW2MoMSw2LDIpXQogICAgCiAgICB7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L25nc2FkbWl4LzNwb3BzX0FkbWl4X2szX3JlcCIsaSwiLnBuZyIpLCBoZWlnaHQgPSAzLjUsIHdpZHRoPTgsIHVuaXQ9ImluIiwgcmVzPTMwMCkKICAgIGJhcnBsb3QodChxWywxOjNdKVssb3JkXSxjb2w9Y29sb3JzLHNwYWNlPTAsYm9yZGVyPU5BLHhheHQ9Im4iLHhsYWI9IiIseWxhYj1wYXN0ZTAoIkFkbWl4dHVyZSBwcm9wb3J0aW9ucyBmb3IgSz0iLGspLCBtYWluPXBhc3RlMCgicmVwIixpKSkKICAgIHRleHQoeGxhYmVscyR4LC0wLjA1LHhsYWJlbHMkcG9wLHhwZD1ULCBzcnQ9OTAsIGFkaj0xLGNleD0wLjgpCiAgICBhYmxpbmUodj1jdW1zdW0oc2FwcGx5KHVuaXF1ZShwb3BvcmRlcltvcmRdKSxmdW5jdGlvbih4KXtzdW0ocG9wW29yZCwiUG9wdWxhdGlvbi5ZZWFyIl09PXgpfSkpLGNvbD0xLGx3ZD0xLjIpCiAgICBkZXYub2ZmKCl9Cn0KCmBgYAoK